/* =========================================================================
 * File: Main.java$
 *
 * Modified by Saverio Miroddi
 *
 * =========================================================================
 * Copyright 2006 by Yuriy Stepovoy.
 * email: stepovoy@gmail.com
 * All rights reserved.
 * =========================================================================
 */
package net.sf.cache4j.perfomance;

import static java.lang.System.out;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import net.sf.cache4j.perfomance.cache.ICacheTest;
import net.sf.cache4j.perfomance.test.ITest;

public class Main {
	private static final String RES_PATH = "resources";
	private static final String CACHES_FILE = "cache.txt";
	private static final String TESTS_FILE  = "test.txt";

	public static void main(String[] args) throws Exception {
		// disable logger for all caches, except for severe errors
		Logger.getLogger("").setLevel(Level.SEVERE);

        int testCount;
        
        if (args != null && args.length == 1) {
        	testCount = Integer.parseInt(args[0]);
        }
        else {
        	testCount = 1;
        }
        
        new Main().run(testCount);
    }

	public void run(int testCount) throws Exception {
        List<String> cacheClassList = getResourcesLines(CACHES_FILE);
        List<String> testClassList = getResourcesLines(TESTS_FILE);
        
        List<ICacheTest> caches = createCacheInstances(cacheClassList);
        List<ITest> tests = createTestInstances(testClassList);
        
        runTests(tests, caches, testCount);
	}
	
	
	private List<String> getResourcesLines(String fileName) throws IOException {
        List<String> lines = new ArrayList<String>();
		
        InputStream in = Main.class.getResourceAsStream(RES_PATH + '/' + fileName);
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        
        String line;
        while ((line = br.readLine()) != null) {
        	line = line.trim();
        	
            if (line.length() > 0 && ! line.startsWith("#")) {
                lines.add(line);
            }
        }        
        br.close();

        return lines;
	}

    private List<ICacheTest> createCacheInstances(List<String> classNames) throws Exception {
        List<ICacheTest> cacheInstances = new ArrayList<ICacheTest>();
        
        for (String className: classNames) {
            // ClassCastException if it isn't an ICache
        	ICacheTest cache = (ICacheTest)Class.forName(className).newInstance();
            cacheInstances.add(cache);
        }

        return cacheInstances;
    }
    
    private List<ITest> createTestInstances(List<String> classNames) throws Exception {
        List<ITest> testInstances = new ArrayList<ITest>();
        
        for (String className: classNames) {
            // ClassCastException if it isn't an ITest
        	ITest test = (ITest)Class.forName(className).newInstance();
            testInstances.add(test);
        }

        return testInstances;
    }


    private void runTests(List<ITest> testList, List<ICacheTest> cacheList, int testCount) {
    	final String TIMING_COL = "%-15s|";
    	
        out.println("----------------------------------------------------------------");
        out.println("java.version=" + System.getProperty("java.version"));
        out.println("java.vm.name=" + System.getProperty("java.vm.name"));
        out.println("java.vm.version=" + System.getProperty("java.vm.version"));
        out.println("java.vm.info=" + System.getProperty("java.vm.info"));
        out.println("java.vm.vendor=" + System.getProperty("java.vm.vendor"));
        out.println("os.name=" + System.getProperty("os.name"));
        out.println("os.version=" + System.getProperty("os.version"));
        out.println("os.arch=" + System.getProperty("os.arch"));
        out.println("----------------------------------------------------------------");
        String testsLine = "               |" + getTestColumns(testList); 
        out.println(testsLine);
        out.println("----------------------------------------------------------------");


        for (int j = 0; j < cacheList.size(); j++) {
            ICacheTest cache = cacheList.get(j);

            StringBuilder lineBuf = new StringBuilder(15 * testCount);
            
            for (int tc = 0; tc < testCount; tc++) {
            	String cacheNameCol = String.format(TIMING_COL, cache.getName());

                for (int i = 0, indx = testList == null ? 0 : testList.size(); i < indx; i++) {
                    ITest test = testList.get(i);

                    try {
                        cache.init();
                        test.init(cache);

                        long start = System.currentTimeMillis();
                        test.test();
                        long stop = System.currentTimeMillis();
                        
                        String timingCol = String.format(TIMING_COL, (stop - start));
                        lineBuf.append(timingCol);

                        test.destroy();
                        cache.destroy();

                        Thread.sleep(1000);
                    }
                    catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
                out.println(cacheNameCol + lineBuf.toString());
            }
        }
        
        out.println("----------------------------------------------------------------");
    }
    
    private String getTestColumns(List<ITest> testList) {
        final String NAME_TMPL = "%-15s|";

        StringBuilder lineBuf = new StringBuilder(21 * testList.size());
        
        for (int i = 0, indx = testList == null ? 0 : testList.size(); i < indx; i++) {
            ITest test = (ITest) testList.get(i);
            
            String nameColumn = String.format(NAME_TMPL, test.getName());
            lineBuf.append(nameColumn);
        }
        
        return lineBuf.toString();
    }
}